package Timesheet;

import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;

import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;

import Timesheet.util.TimesheetDbTransaction;
import Timesheet.util.TsCalendar;

import javax.el.ValueExpression;

public class TimesheetList {

    // Application Properties
    private static TimesheetDbTransaction s_tsDbTran = null;
    private int maxCalendarRows = 10;
    private Date listStartDate = (new GregorianCalendar(2013, 0, 1)).getTime();
    private Date listEndDate = (new GregorianCalendar(2014, 11, 31)).getTime();

    /**
     * @associates <{Timesheet.TimesheetPeriodReport}>
     */
    private static ArrayList s_tsPdRptList = new ArrayList();

    // Application Operation Properties
    private TimesheetPeriodReport editTsPdRpt = new TimesheetPeriodReport();
    private int editTsPdRptId = 0;

    // System Properties
    private String apppath = AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory);
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    private transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);

    public void addNewPeriodReport(int periodSeq) {

        ArrayList tsPdRptList = this.s_tsPdRptList;

        TsCalendar calendar = s_tsDbTran.selectTsCalendarFromDbByPeriodSeq(periodSeq);

        int newSheetID = getNewSheetIDBy(periodSeq);
        int newSheetSeq = getNewSheetSeqBy(periodSeq, newSheetID);

        TimesheetPeriodReport newPeriodReport = new TimesheetPeriodReport(newSheetID, newSheetSeq, calendar, "New");

        // TODO
        this.setEditTsPdRpt(newPeriodReport);
        this.s_tsPdRptList.add(newPeriodReport);
        this.setTsPdRptList(this.s_tsPdRptList); // force to refresh.
    }

    int getNewSheetIDBy(int periodSeq) {
        int sheetID = s_tsDbTran.selectSheetIDFromDbByPeriodSeq(periodSeq); // returns -1, if not found.

        if (-1 == sheetID) {
            // create a new Next sheetID if no sheet exists in DB against the periodSeq.
            int maxSheetIdDb = s_tsDbTran.selectMaxSheetIDFromDb();
            int maxSheetIdInCurrList = getMaxSheetIdInCurrList();
            sheetID = (maxSheetIdDb > maxSheetIdInCurrList ? (maxSheetIdDb + 1) : (maxSheetIdInCurrList + 1));
        }
        return sheetID;
    }

    int getMaxSheetIdInCurrList() {
        int maxSheetID = -1;
        for (int i = 0; i < this.s_tsPdRptList.size(); i++) {
            int sid = ((TimesheetPeriodReport) this.s_tsPdRptList.get(i)).getSheetID();
            maxSheetID = (maxSheetID > sid ? maxSheetID : sid);
        }
        return maxSheetID;
    }

    int getNewSheetSeqBy(int periodSeq, int sheetID) {
        int maxSheetSeq =
            s_tsDbTran.selectMaxSheetSeqByPeriodSeq(periodSeq, sheetID); // returns -1, if periodSeq not found in DB.
        return maxSheetSeq + 1;
    }

    public void editPeriodReport(int editSheetID) {
        // TODO
    }

    public void savePeriodReports() {
        // TODO
        for (int i = 0; i < s_tsPdRptList.size(); i++) {

            TimesheetPeriodReport pdReport = (TimesheetPeriodReport) s_tsPdRptList.get(i);
            String statusBeforeSave = pdReport.getReportedStatus();

            if (pdReport.isChanged() || statusBeforeSave.equals("New")) {

                String statusAfterSave = (statusBeforeSave.equals("New") ? "Saved" : statusBeforeSave);

                if (saveOrUpdatePeriodReportToDb(pdReport, statusAfterSave)) {
                    pdReport.setReportedStatus(statusAfterSave);
                } else {
                    pdReport.setReportedStatus(statusBeforeSave);
                }
            }
        }
    }

    public boolean saveOrUpdatePeriodReportToDb(TimesheetPeriodReport pdReport, String status) {
        this.s_tsDbTran.saveOrUpdatePeriodReportToDb(pdReport, status);
        return true;
    }

    public boolean deletePeriodReportFromDb(int deleteSheetID) { // TODO
        return true;
    }

    public void addProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.addProviderChangeListener(l);
    }

    public void removeProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.removeProviderChangeListener(l);
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }

    public TimesheetList() {
        super();
        if (s_tsDbTran == null) {
            s_tsDbTran = TsApplicationResource.getDbTransaction();
        }
        if (s_tsPdRptList.size() == 0) {
            search();
        }
    }

    public void search() {
        s_tsPdRptList.clear();
        setTsPdRptList(s_tsDbTran.selectTimesheetListBetweenDates(listStartDate, listEndDate, maxCalendarRows));
    }

    public TimesheetPeriodReport[] getTsPdRptList() {
        TimesheetPeriodReport tpr[] = null;
        tpr = (TimesheetPeriodReport[]) s_tsPdRptList.toArray(new TimesheetPeriodReport[s_tsPdRptList.size()]);
        return tpr;
    }

    public void setTsPdRptList(ArrayList tsPdRptList) {
        ArrayList oldTsPdRptList = TimesheetList.s_tsPdRptList;
        TimesheetList.s_tsPdRptList = tsPdRptList;
        propertyChangeSupport.firePropertyChange("tsPdRptList", oldTsPdRptList, tsPdRptList);
        providerChangeSupport.fireProviderRefresh("tsPdRptList");
    }

    public void setListStartDate(Date listStartDate) {
        Date oldListStartDate = this.listStartDate;
        this.listStartDate = listStartDate;
        propertyChangeSupport.firePropertyChange("listStartDate", oldListStartDate, listStartDate);
    }

    public Date getListStartDate() {
        return listStartDate;
    }

    public void setListEndDate(Date listEndDate) {
        Date oldListEndDate = this.listEndDate;
        this.listEndDate = listEndDate;
        propertyChangeSupport.firePropertyChange("listEndDate", oldListEndDate, listEndDate);
    }

    public Date getListEndDate() {
        return listEndDate;
    }

    public void setEditTsPdRpt(TimesheetPeriodReport editTsPdRpt) {
        TimesheetPeriodReport oldEditTsPdRpt = this.editTsPdRpt;
        this.editTsPdRpt = editTsPdRpt;
        propertyChangeSupport.firePropertyChange("editTsPdRpt", oldEditTsPdRpt, editTsPdRpt);
    }

    public TimesheetPeriodReport getEditTsPdRpt() {
        return editTsPdRpt;
    }

    public void setEditTsPdRptId(int editTsPdRptId) {
        this.editTsPdRptId = editTsPdRptId;
    }

    public int getEditTsPdRptId() {
        return editTsPdRptId;
    }
}
